package com.mccree.handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class TimeServerHandler extends ChannelInboundHandlerAdapter {
    /**
     * 如所解释的，channelActive()当建立连接并准备产生流量时，将调用该方法。
     * 让我们写一个代表该方法当前时间的32位整数。
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //要发送新消息，我们需要分配一个新缓冲区，其中将包含该消息。
        // 我们将要编写一个32位整数，因此我们需要一个ByteBuf容量至少为4个字节的。
        // ByteBufAllocator通过获取电流ChannelHandlerContext.alloc()并分配一个新的缓冲区。
        final ByteBuf time = ctx.alloc().buffer(4);
        time.writeInt((int)(System.currentTimeMillis()/1000L+2208988800L));
        //和往常一样，我们编写构造的消息。
        //但是，等等，翻转在哪里？java.nio.ByteBuffer.flip()在NIO中发送消息之前，我们不是曾经打电话过吗？
        // ByteBuf没有这样的方法，因为它有两个指针；
        // 一个用于读取操作，另一个用于写入操作。当您向某处写入内容时，作家索引会增加，ByteBuf而读者索引不会改变。
        // 读者索引和作者索引分别表示消息的开始和结束位置。
        //相反，NIO缓冲区没有提供一种干净的方法来确定消息内容的开始和结束位置，而无需调用flip方法。
        // 当您忘记翻转缓冲区时会遇到麻烦，因为将不会发送任何内容或发送不正确的数据。
        // 在Netty中不会发生这样的错误，因为我们对于不同的操作类型有不同的指针。
        // 您会发现，适应它会使您的生活变得更加轻松-无需翻身的生活！
        //要注意的另一点是ChannelHandlerContext.write()（和writeAndFlush()）方法返回一个ChannelFuture。
        // AChannelFuture表示尚未发生的I / O操作。
        // 这意味着，可能尚未执行任何请求的操作，因为Netty中的所有操作都是异步的。
        // 例如，以下代码甚至在发送消息之前就可能关闭连接：
        //Channel ch = ...;
        //ch.writeAndFlush(message);
        //ch.close();
        //因此，您需要在close()方法ChannelFuture完成后调用该方法，
        // 该write()方法由该方法返回，并在完成写操作后通知其侦听器。
        // 请注意，close()也可能不会立即关闭连接，并且返回ChannelFuture。
        final ChannelFuture f = ctx.writeAndFlush(time);
        f.addListener((ChannelFutureListener) future -> {
            assert f == future;
            ctx.close();
        });
        //当写请求完成时，我们如何得到通知？
        // 这就像将a添加ChannelFutureListener到return一样简单ChannelFuture。
        // 在这里，我们创建了一个新的匿名操作ChannelFutureListener，该匿名Channel操作将在操作完成时关闭。
        //另外，您可以使用预定义的侦听器简化代码：
        //f.addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
